
#pragma once
#include<iostream>
#include<semaphore.h>
#include<vector>
#include<assert.h>
#include<pthread.h>
using namespace std;


static const int gmaxcp=100;
template<class T>
class annulusqueue
{
public:
annulusqueue(const int maxcp=gmaxcp):_maxcp(maxcp),_queue(maxcp)
{
    int n=sem_init(&_spacesem,0,_maxcp);//生产者以空间为信号量，那么初始空间即为队列容量
    assert(n==0);
    (void)n;
    int m=sem_init(&_datasem,0,0);//消费者以数据为信号量，那么初始的数据为0
    assert(m==0);
    (void)m;
    pthread_mutex_init(&_mut,nullptr);
_psetp=_cstep=0;//初始时，生产者和消费者都指向队列的开头即下标为0的位置

}
void P(sem_t &sem)
{
    int n=sem_wait(&sem);//若sem大于0则sem--并且往下走，若不满足条件则阻塞等待
    assert(n==0);//
    (void)n;
}
void V(sem_t &sem)
{
    int n=sem_post(&sem);//资源使用完成归还资源，sem++
    assert(n==0);
    (void)n;
}
void push(const T&in)
{
P(_spacesem);//对空间资源进行P操作即_spacesem--
pthread_mutex_lock(&_mut);
_queue[_psetp++]=in;
_psetp%=_maxcp;
pthread_mutex_unlock(&_mut);

V(_datasem);//对空间资源进行P操作即_datasem++
}

void pop(T* out)
{
    P(_datasem);
pthread_mutex_lock(&_mut);
    *out= _queue[_cstep++];
    _cstep%=_maxcp;
pthread_mutex_unlock(&_mut);

    V(_spacesem);
}

~annulusqueue()
{
    sem_destroy(&_spacesem);//销毁信号量
    sem_destroy(&_datasem);//销毁信号量
    pthread_mutex_destroy(&_mut);
}


    private:
sem_t _spacesem;//生产者对应的信号量--空间资源
sem_t _datasem;//消费者对应的信号量--数据资源
int _maxcp;//环形队列的容量
vector<T> _queue;//环形队列-实际上是数组
int _psetp;//生产者下标
int _cstep;//消费者下标
pthread_mutex_t _mut;
};